package org.hcyspartnoc.luoxin.utils;

import org.hcyspartnoc.luoxin.common.core.configuration.ContrapsychConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Base64;
import java.util.UUID;

/**
 * Wav文件多合一
 *
 * @author yujing 2020年6月15日15:43:20
 */
@Component
public class WavCompose {
    private static final Logger logger = LoggerFactory.getLogger(WavCompose.class);
    private static ContrapsychConfiguration contrapsychConfiguration;

    @Resource
    public void setContrapsychConfiguration(ContrapsychConfiguration contrapsychConfiguration) {
        WavCompose.contrapsychConfiguration = contrapsychConfiguration;
    }

    private int headLength1 = 0;
    private int headLength2 = 0;

    public static int byteArrayToInt(byte[] b) {
        return b[3] & 0xFF | (b[2] & 0xFF) << 8 | (b[1] & 0xFF) << 16 | (b[0] & 0xFF) << 24;
    }

    public static byte[] intToByteArray(int a) {
        return new byte[]{(byte) ((a >> 24) & 0xFF), (byte) ((a >> 16) & 0xFF), (byte) ((a >> 8) & 0xFF), (byte) (a & 0xFF)};
    }

    //字节翻转
    public static byte[] byteToByte(byte[] a) {
        if (a.length == 4)
            return new byte[]{a[3], a[2], a[1], a[0]};
        return null;
    }

    //更改文件头
    private void updateFileHead(String out, boolean ifUpdate) throws IOException {
        RandomAccessFile raf = new RandomAccessFile(out, "rw");
        //long fileLength = raf.length();
        // 打开一个文件通道
        FileChannel channel = raf.getChannel();
        // 映射文件中的某一部分数据以读写模式到内存中
        MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 44);// 文件头长度
        // 修改头部文件
        if (ifUpdate) {
            byte[] head1 = byteToByte(intToByteArray(headLength1));
            byte[] head2 = byteToByte(intToByteArray(headLength2));
            // 进行修改操作
            buffer.put(4, head1[0]);
            buffer.put(5, head1[1]);
            buffer.put(6, head1[2]);
            buffer.put(7, head1[3]);
            buffer.put(40, head2[0]);
            buffer.put(41, head2[1]);
            buffer.put(42, head2[2]);
            buffer.put(43, head2[3]);
            buffer.force();//强制输出，在buffer中的改动生效到文件
        } else {
            //noinspection ConstantConditions
            headLength1 = headLength1 + byteArrayToInt(byteToByte(new byte[]{buffer.get(4), buffer.get(5), buffer.get(6), buffer.get(7)}));
            ;
            //noinspection ConstantConditions
            headLength2 = headLength2 + byteArrayToInt(byteToByte(new byte[]{buffer.get(40), buffer.get(41), buffer.get(42), buffer.get(43)}));
            ;
        }
        buffer.clear();
        channel.close();
        raf.close();
    }

    /**
     * 将多个wav合成一个新的wav
     *
     * @param out 输出文件
     * @param in  输入文件数组
     * @throws IOException
     */
    public void addWav(String out, String... in) {
        try {
            File outFile = new File(out);
//        if (!outFile.getParentFile().exists())
//            outFile.getParentFile().mkdirs();
            if (!outFile.exists())
                outFile.createNewFile();
            OutputStream os = new FileOutputStream(outFile);// 追加
            for (int i = 0; i < in.length; i++) {
                File file1 = new File(in[i]);
                if (!file1.exists())
                    continue;
                //System.out.println(in[i] + "文件长度：" + file1.length());
                InputStream is = new FileInputStream(file1);
                if (i != 0) {
                    //noinspection ResultOfMethodCallIgnored
                    is.skip(44);// 跳过后面的.wav的文件头
                }
                byte[] tempBuffer = new byte[1024];
                int nRed = 0;
                // 将wav全部内容复制到out.wav
                while ((nRed = is.read(tempBuffer)) != -1) {
                    os.write(tempBuffer, 0, nRed);
                    os.flush();
                }
                is.close();
            }
            os.close();
            // 到此完成了in数组全部wav合并成out.wav,但是此时播放out.wav,音频内容仍然只是第一个音频的内容，所以还要更改out.wav的文件头
            for (String s : in) updateFileHead(s, false);
            updateFileHead(out, true);//头部合成
        } catch (Exception ignore) {

        }
    }

    public String addWavToBase64(String... in) {
        File dir = new File(contrapsychConfiguration.getTempFilesDir());
        if (!dir.exists())
            dir.mkdirs();
        UUID uuid = UUID.randomUUID();
        String filePath = contrapsychConfiguration.getTempFilesDir() + uuid + ".wav";
        addWav(filePath, in);
        String toBase64 = convertToBase64(filePath);
        // 删除临时文件
        File file = new File(filePath);
        if (file.exists()) {
            logger.info("删除结果：{}",file.delete());
        }
        return toBase64;
    }

    /**
     * 将WAV文件转换为Base64编码字符串
     *
     * @param filePath WAV文件的路径
     * @return Base64编码的字符串
     * @throws IOException 如果读取文件时发生错误
     */
    public static String convertToBase64(String filePath) {
        try {
            File file = new File(filePath);
            FileInputStream fis = new FileInputStream(file);

            // 读取文件到byte数组
            byte[] fileBytes = new byte[(int) file.length()];
            fis.read(fileBytes);
            fis.close();

            // 使用Base64编码byte数组
            return Base64.getEncoder().encodeToString(fileBytes);
        } catch (Exception ignore) {
            return null;
        }
    }

}
